#pragma once
#include "gtest/gtest.h"
#include "SGFem/ElementCalculator/Factory/ElementCalculatorFactory.h"
#include "DataStructure/Input/Material/ThermalMaterial.h"
#include "../Hexa8ThermalCalculator.h"


using SG::Algebra::Matrix;
using SG::DataStructure::Common::Real;
using SG::DataStructure::FEM::ThermalMaterial;
using namespace SG::DataStructure::FEM;
using namespace SG::FEMSolver::Element;

// ElementCalculatorFactory 是否正确创建单元计算类
// 将 ElementCalculatorFactory 的 Register和生成对象测试放置在具体单元类型计算中
TEST (ElementCalculatorFactoryTest, Hexa8ThermalElement)
{
    ElementCalculatorFactory::Register (ElementTypes::ELETYPE_Hexa8SRI, Hexa8ThermalCalculator::Create);

    // Test
    auto CalculatorPtr = ElementCalculatorFactory::Create (ElementTypes::ELETYPE_Hexa8SRI);

    // Target data
    auto hexa8Calctor = dynamic_cast<Hexa8ThermalCalculator*> (CalculatorPtr.get ());

    // Check
    ASSERT_TRUE (0 != hexa8Calctor);
}
extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

class Hexa8ThermalCalculatorTest : public ::testing::Test
{
public:

    virtual void SetUp() override
    {
        // 指定材料属性
        points = SG::Algebra::PointArray(8);
        points[0].m_x = 0;  points[0].m_y = 1;  points[0].m_z = 2;
        points[1].m_x = 0;  points[1].m_y = 0;  points[1].m_z = 2;
        points[2].m_x = 0;  points[2].m_y = 0;  points[2].m_z = 0;
        points[3].m_x = 0;  points[3].m_y = 1;  points[3].m_z = 0;
        points[4].m_x = 1;  points[4].m_y = 1;  points[4].m_z = 2; 
        points[5].m_x = 1;  points[5].m_y = 0;  points[5].m_z = 2;
        points[6].m_x = 1;  points[6].m_y = 0;  points[6].m_z = 0; 
        points[7].m_x = 1;  points[7].m_y = 1;  points[7].m_z = 0;
    }

protected:
    SG::Algebra::PointArray points; ///< 单元节点坐标
};

TEST_F (Hexa8ThermalCalculatorTest, ComputeStiffness)
{
    ThermalMaterial material;
    material.m_K = 1.0;
    
    Matrix coord(8,3);
    for (std::size_t iNode = 0; iNode < 8; ++iNode)
    {
        coord(iNode, 0) = points[iNode].m_x;
        coord(iNode, 1) = points[iNode].m_y;
        coord(iNode, 2) = points[iNode].m_z;
    }
    
    Matrix Kel(8, 8);
    Hexa8ThermalCalculator elementCalc;
    elementCalc.Initialize(ELETYPE_Hexa8SRI);
    elementCalc.ComputeStiffness(coord, material, Kel);
    
    Matrix KelTarget(8, 8, {          
        0.50000000000000     ,  -0.83333333333335E-01,   -0.83333333333334E-01,   0.16666666666667     ,   -0.83333333333335E-01,  -0.20833333333333    ,   -0.12500000000000    ,   -0.83333333333334E-01,
        -0.83333333333335E-01,  0.50000000000000     ,   0.16666666666667     ,   -0.83333333333334E-01,   -0.20833333333333    ,  -0.83333333333335E-01,   -0.83333333333334E-01,   -0.12500000000000    ,
        -0.83333333333334E-01,  0.16666666666667     ,   0.50000000000000     ,   -0.83333333333335E-01,   -0.12500000000000    ,  -0.83333333333334E-01,   -0.83333333333336E-01,   -0.20833333333333    ,
        0.16666666666667     ,  -0.83333333333334E-01,   -0.83333333333335E-01,   0.50000000000000     ,   -0.83333333333334E-01,  -0.12500000000000    ,   -0.20833333333333    ,   -0.83333333333335E-01,
        -0.83333333333335E-01,  -0.20833333333333    ,   -0.12500000000000    ,   -0.83333333333334E-01,   0.50000000000000     ,  -0.83333333333335E-01,   -0.83333333333334E-01,   0.16666666666667     ,
        -0.20833333333333    ,  -0.83333333333335E-01,   -0.83333333333334E-01,   -0.12500000000000    ,   -0.83333333333335E-01,  0.50000000000000     ,   0.16666666666667     ,   -0.83333333333334E-01, 
        -0.12500000000000    ,  -0.83333333333334E-01,   -0.83333333333336E-01,   -0.20833333333333    ,   -0.83333333333334E-01,  0.16666666666667     ,   0.50000000000000     ,   -0.83333333333335E-01, 
        -0.83333333333334E-01,  -0.12500000000000    ,   -0.20833333333333    ,   -0.83333333333335E-01,   0.16666666666667     ,  -0.83333333333334E-01,   -0.83333333333335E-01,   0.50000000000000 
         });
    
    ASSERT_TRUE(Kel == KelTarget);
}